#ifndef HTTP_REQUEST_H
#define HTTP_REQUEST_H

#include "../../../tcp/code/utility/Timestamp.h"

#include <unordered_map>

class HttpRequest
{
public:
    enum class Method
    {
        Invalid,
        Get,
        Post,
        Put,
        Delete,
        Head,
        Options // 不是Option
    };

    enum class Version
    {
        Unknown,
        Http10,
        Http11
    };

    HttpRequest()
        : method_(Method::Invalid),
          version_(Version::Unknown)
    {
    }

    bool setMethod(const char *begin, const char *end) // 返回是否合法
    {
        std::string m(begin, end);
        if (m == "GET")
        {
            this->method_ = Method::Get;
        }
        else if (m == "POST")
        {
            this->method_ = Method::Post;
        }
        else if (m == "PUT")
        {
            this->method_ = Method::Put;
        }
        else if (m == "DELETE")
        {
            this->method_ = Method::Delete;
        }
        else if (m == "HEAD")
        {
            this->method_ = Method::Head;
        }
        else if (m == "OPTIONS")
        {
            this->method_ = Method::Options;
        }
        else
        {
            this->method_ = Method::Invalid;
        }
        return this->method_ != Method::Invalid;
    }
    Method getMethod() const
    {
        return this->method_;
    }
    std::string getMethodName() const
    {
        std::string methodName{};
        if (this->method_ == Method::Get)
        {
            methodName = "GET";
        }
        else if (this->method_ == Method::Post)
        {
            methodName = "POST";
        }
        else if (this->method_ == Method::Put)
        {
            methodName = "PUT";
        }
        else if (this->method_ == Method::Delete)
        {
            methodName = "DELETE";
        }
        else if (this->method_ == Method::Head)
        {
            methodName = "HEAD";
        }
        else
        {
            methodName = "UNKNOWN";
        }
        return methodName;
    }

    void setVersion(Version verson)
    {
        this->version_ = verson;
    }
    Version getVersion() const
    {
        return this->version_;
    }
    std::string getVersionName() const
    {
        std::string versionName{};
        if (this->version_ == Version::Http10)
        {
            versionName = "HTTP/1.0";
        }
        else if (this->version_ == Version::Http11)
        {
            versionName = "HTTP/1.1";
        }
        else
        {
            versionName = "UNKNOWN";
        }
        return versionName;
    }

    void setPath(const char *begin, const char *end)
    {
        this->path_.assign(begin, end);
    }
    std::string getPath() const
    {
        return this->path_;
    }

    void setPathParameters(const std::string &key, const std::string &value)
    {
        this->pathParameters_[key] = value;
    }
    std::string getPathParameters(const std::string &key) const
    {
        auto it = this->pathParameters_.find(key);
        if (it == this->pathParameters_.end())
        {
            return "";
        }
        return it->second;
    }

    void setQueryParameters(const char *begin, const char *end)
    {
        std::string paramStr(begin, end);

        // 按 & 分割多个参数
        std::string::size_type andPos{};
        std::string::size_type prePos = 0;
        std::string::size_type equalPos{};
        while ((andPos = paramStr.find('&', prePos)) != std::string::npos)
        {
            std::string pair = paramStr.substr(prePos, andPos - prePos);

            // 按 = 分割键值对
            equalPos = pair.find('=');
            if (equalPos != std::string::npos)
            {
                std::string key = pair.substr(0, equalPos);
                std::string value = pair.substr(equalPos + 1);
                this->queryParameters_[key] = value;
            }

            prePos = andPos + 1;
        }

        // 处理最后一个参数
        std::string lastPair = paramStr.substr(prePos);
        equalPos = lastPair.find('=');
        if (equalPos != std::string::npos)
        {
            std::string key = lastPair.substr(0, equalPos);
            std::string value = lastPair.substr(equalPos + 1);
            this->queryParameters_[key] = value;
        }
    }
    std::string getQueryParameters(const std::string &key) const
    {
        auto it = this->queryParameters_.find(key);
        if (it == queryParameters_.end())
        {
            return "";
        }
        return it->second;
    }

    void setHeader(const char *begin, const char *colonPos, const char *end)
    {
        std::string key(begin, colonPos);

        ++colonPos;
        while (colonPos < end && isspace(*colonPos)) // 跳过空格
        {
            ++colonPos;
        }

        std::string value(colonPos, end);
        // value截断丢掉后面的空格
        while (!value.empty() && isspace(value[value.size() - 1]))
        {
            value.resize(value.size() - 1);
        }

        this->headers_[key] = value;
    }
    std::string getHeader(const std::string &key) const
    {
        auto it = this->headers_.find(key);
        if (it == this->headers_.end())
        {
            return "";
        }
        return it->second;
    }
    std::unordered_map<std::string, std::string> getHeaders() const
    {
        return this->headers_;
    }

    void setBody(const char *begin, const char *end)
    {
        if (begin <= end)
        {
            this->body_.assign(begin, end - begin);
        }
    }
    void setBody(const std::string &body)
    {
        this->body_ = body;
    }
    std::string getBody() const
    {
        return this->body_;
    }
    void setBodyLength(int bodyLength)
    {
        this->bodyLength_ = bodyLength_;
    }
    int getBodyLength() const
    {
        return this->bodyLength_;
    }

    void setReceiveTime(Timestamp receiveTime)
    {
        this->receiveTime_ = receiveTime;
    }
    Timestamp receiveTime() const
    {
        return this->receiveTime_;
    }

    // 临时对象传给当前对象置空，临时对象再析构
    void swap(HttpRequest &other)
    {
        std::swap(this->method_, other.method_); // 允许类的成员函数对同类对象的私有成员操作
        std::swap(this->version_, other.version_);
        std::swap(this->path_, other.path_);
        std::swap(pathParameters_, other.pathParameters_);
        std::swap(queryParameters_, other.queryParameters_);
        std::swap(this->headers_, other.headers_);

        std::swap(this->receiveTime_, other.receiveTime_);
    }

private:
    Method method_;
    Version version_;
    std::string path_;                                             // url，get ?前的路径
    std::unordered_map<std::string, std::string> pathParameters_;  // 路径参数，如模板/{id}/{name} -> 实际/a/b 进行对应
    std::unordered_map<std::string, std::string> queryParameters_; // get的查询参数
    std::unordered_map<std::string, std::string> headers_;
    std::string body_;
    int bodyLength_;

    Timestamp receiveTime_; // 请求时间
};

#endif // HTTP_REQUEST_H